package com.ruoyi.slope.api.service.impl;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.Base64ToMultipartFile;
import com.ruoyi.common.utils.file.FileUploadUtils;
import com.ruoyi.slope.api.domain.SlopeAiPhoto;
import com.ruoyi.slope.api.service.ISlopeAiPhotoService;
import com.ruoyi.slope.api.service.SlopeApiService;
import com.ruoyi.slope.video.device.domain.SlopeVideoDevice;
import com.ruoyi.slope.video.device.service.ISlopeVideoDeviceService;
import com.ruoyi.slope.video.radar.domain.*;
import com.ruoyi.slope.video.radar.service.IRadarMonitoringDataService;
import com.ruoyi.slope.video.radar.service.IRadarMonitoringDeformationService;
import com.ruoyi.slope.video.radar.service.IRadarMonitoringPngService;
import lombok.Getter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.text.SimpleDateFormat;
import java.util.*;

@Service
public class SlopeApiServiceImpl implements SlopeApiService {

    @Autowired
    private ISlopeVideoDeviceService slopeVideoDeviceService;

    @Autowired
    private IRadarMonitoringDeformationService radarMonitoringDeformationService;

    private static String defaultBaseDir = RuoYiConfig.getProfile();

    @Getter
    private static List<SlopeVideoDevice> devices = new ArrayList<>();

    @PostConstruct
    public void init() {
        refreshDevices();
    }

    // 每10分钟刷新一次（10 * 60 * 1000 毫秒）
    @Scheduled(fixedRate = 10 * 60 * 1000)
    public void refreshDevices() {
        List<SlopeVideoDevice> newDevices = slopeVideoDeviceService
                .selectSlopeVideoDeviceList(new SlopeVideoDevice());

        if (newDevices == null || newDevices.isEmpty()) {
            System.err.println("❌ 未配置任何雷达设备，请检查设备配置！");
        }

        devices = newDevices;
        System.out.println("设备列表已刷新，共 " + devices.size() + " 个设备。");
    }

    @Autowired
    private ISlopeAiPhotoService slopeAiPhotoService;

    @Autowired
    private IRadarMonitoringPngService radarMonitoringPngService;

    @Autowired
    private IRadarMonitoringDataService radarMonitoringDataService;

    @Override
    public AjaxResult handleUploadAiImage(Map<String, Object> payload) {
        try {
            String deviceId = (String) payload.get("device_id");
            String imgBase64 = (String) payload.get("img_base64");

            if (imgBase64 == null || imgBase64.isEmpty()) {
                return AjaxResult.error("图片数据不能为空");
            }
            String slopeId = null;
            for (SlopeVideoDevice device : devices){
                if(device.getDeviceId().equals(deviceId)){
                    slopeId = device.getDeviceId();
                }
            }

            if (slopeId == null) {
                return AjaxResult.error("未找到对应的边坡编号，deviceId=" + deviceId);
            }

            String fileName = "slope_" + System.currentTimeMillis() + ".jpg";
            MultipartFile file = Base64ToMultipartFile.base64ToMultipart(imgBase64, fileName);

            String savedFileName = FileUploadUtils.upload(defaultBaseDir, file);

            SlopeAiPhoto photo = new SlopeAiPhoto();
            photo.setDeviceId(deviceId);
            photo.setSlopeId(slopeId);  // 把边坡编号写入
            photo.setPicPath(savedFileName);
            slopeAiPhotoService.insertSlopeAiPhoto(photo);

            return AjaxResult.success("上传成功");
        } catch (Exception e) {
            e.printStackTrace();
            return AjaxResult.error("上传失败：" + e.getMessage());
        }
    }


    @Override
    public AjaxResult handleDeviceData(HttpServletRequest request, Integer type) {
        try {
            if (type != null && type == 2) {
                return handleJsonData(request);
            } else if (type != null && type == 3) {
                return handleImageFragment(request);
            } else {
                return AjaxResult.error("type参数无效");
            }
        } catch (Exception e) {
            e.printStackTrace();
            return AjaxResult.error("处理失败：" + e.getMessage());
        }
    }

    private AjaxResult handleJsonData(HttpServletRequest request) throws IOException {
        if (!request.getContentType().contains("application/json")) {
            return AjaxResult.error("Content-Type 必须为 application/json");
        }

        ObjectMapper objectMapper = new ObjectMapper();
        Map<String, Object> payload = objectMapper.readValue(request.getInputStream(), Map.class);

        if (payload == null) {
            return AjaxResult.error("请求体不能为空");
        }

        System.out.println("接收到测点JSON数据: " + payload);

        String deviceId = (String) payload.get("deviceId");
        String apiKey = (String) payload.get("apikey");
        SlopeVideoDevice slopeVideoDevice = null;
        for (SlopeVideoDevice device : devices){
            if(device.getDeviceId().equals(deviceId)){
                slopeVideoDevice = device;
            }
        }
        if (slopeVideoDevice == null || !slopeVideoDevice.getDeviceKey().equals(apiKey)) {
            return AjaxResult.error("鉴权失败，deviceId 或 apiKey 不正确");
        }


        Map<String, Object> data = (Map<String, Object>) payload.get("data");

        List<RadarMonitoringData> records = new ArrayList<>();

        if (data != null) {
            for (Map.Entry<String, Object> deviceEntry : data.entrySet()) {
                String devId = deviceEntry.getKey(); // 设备id（冗余，和 deviceId 一致）

                Map<String, Object> pointMap = (Map<String, Object>) deviceEntry.getValue();
                for (Map.Entry<String, Object> pointEntry : pointMap.entrySet()) {
                    String measurementPointCode = pointEntry.getKey(); // 测点编号

                    Map<String, Object> timeValueMap = (Map<String, Object>) pointEntry.getValue();
                    for (Map.Entry<String, Object> tv : timeValueMap.entrySet()) {
                        String timeStr = tv.getKey();  // 时间字符串
                        String valueStr = String.valueOf(tv.getValue());

                        try {
                            Date dataTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(timeStr);

                            RadarMonitoringData entity = new RadarMonitoringData();
                            entity.setRadarDetectionId(deviceId); // 或者 devId
                            entity.setMeasurementPointCode(measurementPointCode);
                            entity.setDataTime(dataTime);
                            entity.setDataValue(new BigDecimal(valueStr));
                            entity.setSlopeId(slopeVideoDevice.getSlopeId());
                            records.add(entity);

                        } catch (Exception e) {
                            System.err.println("时间解析失败: " + timeStr);
                        }
                    }
                }
            }
        }

        if (!records.isEmpty()) {
            for (RadarMonitoringData record : records) {
                radarMonitoringDataService.insertRadarMonitoringData(record);
            }
        }

        return AjaxResult.success("接收成功，共保存 " + records.size() + " 条数据");
    }

    private AjaxResult handleImageFragment(HttpServletRequest request) throws Exception {
        if (!request.getContentType().contains("application/octet-stream")) {
            return AjaxResult.error("Content-Type 必须为 application/octet-stream");
        }

        // 读取数据
        byte[] data = readBytes(request.getInputStream());
        if (data.length < 4) {
            return AjaxResult.error("数据长度不足");
        }

        // 解析头信息
        int jsonLen = ((data[0] & 0xFF) << 8) | (data[1] & 0xFF);
        int picLen = ((data[2 + jsonLen] & 0xFF) << 8) | (data[3 + jsonLen] & 0xFF);

        byte[] jsonBytes = Arrays.copyOfRange(data, 2, 2 + jsonLen);
        byte[] picBytes = Arrays.copyOfRange(data, 4 + jsonLen, 4 + jsonLen + picLen);

        // 解析 JSON
        ObjectMapper objectMapper = new ObjectMapper();
        Map<String, Object> jsonMap = objectMapper.readValue(new String(jsonBytes, StandardCharsets.UTF_8), Map.class);
        System.out.println("图片JSON数据: " + jsonMap);

        // 鉴权校验
        String deviceId = (String) jsonMap.get("did");
        SlopeVideoDevice slopeVideoDevice = null;
        for (SlopeVideoDevice device : devices){
            if(device.getDeviceId().equals(deviceId)){
                slopeVideoDevice = device;
            }
        }
        if (slopeVideoDevice == null) {
            return AjaxResult.error("鉴权失败，deviceId 不正确");
        }

        // 获取元信息
        String desc = (String) jsonMap.get("desc"); // 例如 "1-2-90813"
        String[] descParts = desc.split("-");
        int index = Integer.parseInt(descParts[0]);   // 当前分片索引
        int total = Integer.parseInt(descParts[1]);   // 总分片数

        long at = Long.parseLong(String.valueOf(jsonMap.get("at")));
        String fileType = (String) jsonMap.get("file_type");

        // 临时目录
        File tempDir = new File(defaultBaseDir, "temp/" + at);
        if (!tempDir.exists()) tempDir.mkdirs();

        // 存储分片
        File partFile = new File(tempDir, index + "." + fileType);
        try (FileOutputStream fos = new FileOutputStream(partFile)) {
            fos.write(picBytes);
        }

        String field = (String) jsonMap.get("field");

        RadarMonitoringBase png = RadarMonitoringFactory.create(field);

        // 保存数据库记录（可选：只保存元数据）
        png.setAtTime(new Date(at));
        png.setDescription(desc);
        png.setDid((String) jsonMap.get("did"));
        png.setSlopeId(slopeVideoDevice.getSlopeId());
        png.setDsId((String) jsonMap.get("ds_id"));
        png.setField(field);
        png.setFileType(fileType);
        png.setImgPath(partFile.getAbsolutePath());
        // 设置经纬度和设备id
        Map<String, Object> attrs = (Map<String, Object>) jsonMap.get("attrs");
        if (attrs != null) {
            png.setLatmax(attrs.get("latmax") != null ? new BigDecimal(attrs.get("latmax").toString()) : null);
            png.setLatmin(attrs.get("latmin") != null ? new BigDecimal(attrs.get("latmin").toString()) : null);
            png.setLngmax(attrs.get("lngmax") != null ? new BigDecimal(attrs.get("lngmax").toString()) : null);
            png.setLngmin(attrs.get("lngmin") != null ? new BigDecimal(attrs.get("lngmin").toString()) : null);
        }

        png.setDeviceId(png.getDid()); // ✅ 把 did 作为设备id 存进去
        // 检查是否收齐
        File[] parts = tempDir.listFiles((dir, name) -> name.endsWith("." + fileType));
        if (parts != null && parts.length == total) {
            // 合成完整文件
            File finalFile = new File(defaultBaseDir + "/complete", at + "." + fileType);
            finalFile.getParentFile().mkdirs(); // 确保目录存在

            try (FileOutputStream fos = new FileOutputStream(finalFile)) {
                for (int i = 0; i < total; i++) {
                    File f = new File(tempDir, i + "." + fileType);
                    Files.copy(f.toPath(), fos);
                }
            }

            // 转成 MultipartFile
            MultipartFile multipartFile = new MockMultipartFile(
                    finalFile.getName(),
                    finalFile.getName(),
                    "application/octet-stream",
                    new FileInputStream(finalFile)
            );

            // 用上传工具类保存
            String savedFileName = FileUploadUtils.upload(defaultBaseDir, multipartFile);

            // 更新数据库，记录完整文件路径
            png.setImgPath(savedFileName);
            if (png instanceof RadarMonitoringPng) {
                radarMonitoringPngService.insertRadarMonitoringPng((RadarMonitoringPng) png);
            } else if (png instanceof RadarMonitoringDeformation) {
                radarMonitoringDeformationService.insertRadarMonitoringDeformation((RadarMonitoringDeformation) png);
            }


            // 清理临时分片文件
            for (File f : parts) {
                f.delete();
            }

            // 清理空目录
            if (tempDir.exists() && tempDir.isDirectory()) {
                tempDir.delete();
            }

            return AjaxResult.success("所有分片已合成", savedFileName);
        }

        return AjaxResult.success("分片接收成功，等待合并", partFile.getAbsolutePath());
    }

    private byte[] readBytes(InputStream is) throws IOException {
        ByteArrayOutputStream buffer = new ByteArrayOutputStream();
        byte[] tmp = new byte[1024];
        int len;
        while ((len = is.read(tmp)) != -1) buffer.write(tmp, 0, len);
        return buffer.toByteArray();
    }

}
